package com.qinker.robot.hook;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.sky.xposed.common.util.Alog;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;


public class HookMain implements IXposedHookLoadPackage {
    public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {

        if (!StringUtils.equals(Constant.Rimet.PACKAGE_NAME, lpparam.packageName)
                || !StringUtils.equals(Constant.Rimet.PACKAGE_NAME, lpparam.processName)) {
            return;
        }
        String className = "com.alibaba.android.dingtalk.live.LiveInterfaceImpl";
        //Log.i("DING_TEST", "DING 进入HOOK1");
        //attachFindClass(className);
        Class<?> messageImpl = XposedHelpers.findClass(className, lpparam.classLoader);
        Log.i("DING_TEST", "DING 进入HOOK1" + messageImpl);

        Method[] methods = messageImpl.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++) {
            int finali = i;
            if (filterMethod(methods[i])) {

                Log.i("DING_TEST", "hook method: " + methods[i].getName() + "@" + methods[i].getParameterTypes().length);
                XposedBridge.hookMethod(methods[i], new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Log.i("DING_TEST", "进入方法: " + methods[finali].getName() + "@" + StringUtils.join(param.args, ","));
                        if (param.args != null) {
                            for (int j = 0; j < param.args.length; j++) {
                                if (param.args[j].getClass().getName().contains("LauncherApplication")) {
                                    continue;
                                }
                                Log.i("DING_TEST", "after" + (j + 1) + "个参数: " + JSON.toJSONString(param.args[j]));
                            }
                        }
                        Log.i("DING_TEST", "堆栈: ", new Exception());
                    }

                    @Override
                    protected void afterHookedMethod(MethodHookParam param) {

                    }
                });
            }
        }
      /*  Object contactSearchPresenter = XposedHelpers.findClass("gyc", lpparam.classLoader).getDeclaredConstructor(Activity.class, View.class).newInstance(null, null);
        XposedHelpers.callMethod(contactSearchPresenter, "a", "100617222327004434", false);*/
       /* findAndHookMethod(
                messageImpl,
                "a",
                String.class,
                List.class,
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Log.i("DING_TEST", "before:第1个参数: " + JSON.toJSONString(param.args[0]));
                        Log.i("DING_TEST", "before:第2个参数: " + JSON.toJSONString(param.args[1]));
     *//*                   String c = (String) XposedHelpers.getObjectField(param.thisObject, "a");
                        Log.i("DING_TEST", "before:a: " + JSON.toJSONString(c));*//*
                    }

                    //方法执行后执行,修改方法的返回值的地方
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) {
                        //Log.i("DING_TEST", "after:第1个参数: " + JSON.toJSONString(param.args[0]));
                        *//*String c = (String) XposedHelpers.getObjectField(param.thisObject, "a");
                        Log.i("DING_TEST", "after:a: " + JSON.toJSONString(c));*//*
                    }
                }
        );*/

       /* findAndHookMethod(
                className,
                lpparam.classLoader,
                "b",
                String.class,
                new XC_MethodHook() {
                    @Override
                    protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                        Log.i("DING_TEST", "before第1个参数: " + JSON.toJSONString(param.args[0]));

                    }

                    //方法执行后执行,修改方法的返回值的地方
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) {
                        Log.i("DING_TEST", "before第1个参数: " + JSON.toJSONString(param.args[0]));
                    }
                }
        );*/


        /*Class<?> imEngineClass = XposedHelpers.findClass("com.alibaba.wukong.im.IMEngine", lpparam.classLoader);
        Class<?> messageClass = XposedHelpers.findClass("com.alibaba.wukong.im.Message", lpparam.classLoader);
        Class<?> conversationServiceClass = XposedHelpers.findClass("com.alibaba.wukong.im.ConversationService", lpparam.classLoader);
        Object conversationService = XposedHelpers.callStaticMethod(imEngineClass, "getIMService", conversationServiceClass);

        Method createConversationMethod = conversationServiceClass.getDeclaredMethod("createConversation", Callback.class, String.class, String.class, messageClass, int.class, Long.class);
        createConversationMethod.invoke(conversationService, new Callback<Object>() {
            @Override
            public void onException(String str, String str2) {

            }

            @Override
            public void onProgress(Object o, int i) {

            }

            @Override
            public void onSuccess(Object o) {
                Log.d("DING_tEST", JSON.toJSONString(o));
            }
        }, "", "", null, 1, 242242863L);*/
        Log.i("DING_TEST", "DING 进入HOOK2");
    }


    private void attachFindClass(String strClazz) {
        XposedHelpers.findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                ClassLoader cl = ((Context) param.args[0]).getClassLoader();
                Class<?> clazz = cl.loadClass(strClazz);

                //XposedBridge.log("HookedClass : "+strClazz);
                // 获取到指定名称类声明的所有方法的信息
                Method[] m = clazz.getDeclaredMethods();
                // 打印获取到的所有的类方法的信息
                for (Method method : m) {

                    //XposedBridge.log("HOOKED CLASS-METHOD: "+strClazz+"-"+m[i].toString());
                    if (!Modifier.isAbstract(method.getModifiers())           // 过滤掉指定名称类中声明的抽象方法
                            && !Modifier.isNative(method.getModifiers())     // 过滤掉指定名称类中声明的Native方法
                            && !Modifier.isInterface(method.getModifiers())  // 过滤掉指定名称类中声明的接口方法
                    ) {

                        // 对指定名称类中声明的非抽象方法进行java Hook处理
                        XposedBridge.hookMethod(method, new XC_MethodHook() {

                            // 被java Hook的类方法执行完毕之后，打印log日志
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                // 打印被java Hook的类方法的名称和参数类型等信息
                                Alog.i("HOOKED METHOD: " + strClazz + "-" + param.method.toString());
                            }
                        });
                    }
                }
            }
        });
    }

    private boolean filterMethod(Method method) {
        // 过滤掉指定名称类中声明的抽象方法
        return !Modifier.isAbstract(method.getModifiers())
                // 过滤掉指定名称类中声明的Native方法
                && !Modifier.isNative(method.getModifiers())
                // 过滤掉指定名称类中声明的接口方法
                && !Modifier.isInterface(method.getModifiers())
                && !("decode".equals(method.getName()))
                && !("getClass".equals(method.getName()))
                && !("equals".equals(method.getName()))
                && !("clone".equals(method.getName()))
                && !("hashCode".equals(method.getName())
                && !("toString".equals(method.getName()))
                && !("wait".equals(method.getName())));
    }
}


